/*
 * entradaSala.cpp
 *
 *  Created on: 01/07/2014
 *      Author: nicolas
 */

#include "../interfaces/iPersona.h"
#include "../ipc/Semaforo.h"
#include "../comun/SalaDePersonas.h"
#include "../defines.h"
#include "../comun/ServidorIDs.h"
#include <stdlib.h>
#include <syslog.h>
#include <stdio.h>
#include "../comun/iSemaforo.h"
#include "../comun/ServidorRemoto.h"
#include "../ipcRemoto/SemaforoRemoto.h"
#include "../comun/SalaRemota.h"

void reservarLugar(iSemaforo* sem, SalaDePersonas* sala, int id) {
	sem->wait();
	sala->reservarLugar(id);
	sem->signal();
}

int colocarEnReserva(SalaDePersonas* sala, int id) {
	sala->colocarEnReserva(id);
	return sala->cantidadDePersonas();
}

void verificarBus(SalaDePersonas* sala, SalaDePersonas* otraSala,
		iSemaforo* semBus, iSemaforo* semOtraSala, iSemaforo* semSalaActual) {
	syslog(LOG_INFO, "Verifica al bus");
	bool busEsperando = (sala->estadoBUS() == Tipos::BUS_PARADO);
	if (busEsperando) {
		syslog(LOG_INFO, "Desperto al bus en la sala actual");
		sala->BUSDespierto();
		semBus->signal();
	} else {
		semSalaActual->signal();

		semOtraSala->wait();
		busEsperando = (otraSala->estadoBUS() == Tipos::BUS_PARADO);
		if (busEsperando) {
			syslog(LOG_INFO, "Desperto al bus en la otra sala");
			otraSala->BUSDespierto();
			semBus->signal();
		}
		semOtraSala->signal();

		semSalaActual->wait();
	}
}

int main(int argc, char **argv) {

	if (argc != 3) {
		//error
		exit(1);
	}

	int numeroSala = atoi(argv[1]);
	Tipos::LugarDeSala lugarSala = (Tipos::LugarDeSala) atoi(argv[2]);

	char encabezado[80];
	sprintf(encabezado, "entradaSala numero %i,lugar %i", numeroSala,
			lugarSala);

	openlog(encabezado, LOG_PID | LOG_CONS, LOG_LOCAL0);

	syslog(LOG_INFO, "Se inicio entradaSala con args: %s, %s", argv[1],
			argv[2]);

	ServidorRemoto rpc;
	int idSala = rpc.pedirIdSala(numeroSala, Tipos::TP_ENTRADA_SALA, lugarSala);
	int idBroker = rpc.idBrokerConectado();
	rpc.pedirIdSala(numeroSala, Tipos::TP_ENTRADA_COLA, lugarSala);

	int lleno, semShmem, semOtroShmem;

	Tipos::LugarDeSala lugarOtraSala;

	if (lugarSala == Tipos::LUGAR_ENTRADA) {

		lugarOtraSala = Tipos::LUGAR_ZOO;
		lleno = ID_SEM_SALA_ENT_LLENO(numeroSala);
		semShmem = ID_MUTEX_SALA_ENT(numeroSala);
		semOtroShmem = ID_MUTEX_SALA_ZOO(numeroSala);

	} else {

		lugarOtraSala = Tipos::LUGAR_ENTRADA;
		lleno = ID_SEM_SALA_ZOO_LLENO(numeroSala);
		semShmem = ID_MUTEX_SALA_ZOO(numeroSala);
		semOtroShmem = ID_MUTEX_SALA_ENT(numeroSala);

	}

	bool salir = false;

	iPersona persona(numeroSala, lugarSala);
	iSemaforo* sem = new SemaforoRemoto(semShmem, idSala, idBroker);
	iSemaforo* semOtra = new SemaforoRemoto(semOtroShmem, idSala, idBroker);
	iSemaforo* semLleno = new SemaforoRemoto(lleno, idSala, idBroker);
	iSemaforo* semBus = new SemaforoRemoto(ID_SEM_BUS(numeroSala), idSala,
			idBroker);
	SalaRemota shmemSala(numeroSala, lugarSala, idSala, idBroker);
	SalaRemota shmemOtra(numeroSala, lugarOtraSala, idSala, idBroker);

	int cant, id;

	while (!salir) {
		id = persona.recibirPeticionEntrar();
		syslog(LOG_INFO, "Recibio peticion de entrar de %i", id);
		reservarLugar(sem, &shmemSala, id);
		persona.permitirAcceso(id);
		syslog(LOG_INFO, "Permitio acceso de %i", id);
		persona.recibirInformeAcceso();
		syslog(LOG_INFO, "Recibio confirmacion");
		sem->wait();
		cant = colocarEnReserva(&shmemSala, id);
		syslog(LOG_INFO, "Coloco en reserva a %i", id);
		if (cant >= 1) {
			verificarBus(&shmemSala, &shmemOtra, semBus, semOtra, sem);
		}
		sem->signal();
		if (cant == CANTMAX)
			semLleno->wait();

	}

}

